﻿using FlyIL.Expression;
using FlyIL.Misc;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

namespace FlyIL.Trace;

class TraceRoot
{
    protected List<TraceRoot> alist;


    /// <summary>
    /// 默认 权重是 1 
    /// </summary>
    [DebuggerNonUserCode()]
    protected virtual int Order() => 1;


    [DebuggerNonUserCode()]
    bool _(Type type)
    {
        return type.BaseType == (this.GetType());
    }


    /// <summary>
    /// 查找分支处理 
    /// </summary>
    //[DebuggerNonUserCode()]
    public TraceRoot GetSubMatch(Inst inst, List<Operand> ops)
    {
        lock (this)
        {

            if (alist == null)
            {
                alist = new();

                var types = Assembly.GetCallingAssembly().GetTypes().Where(_).ToList();


                foreach (var t in types)
                {
                    if (!t.IsAbstract)
                    {
                        object obj = Activator.CreateInstance(t);
                        alist.Add(obj as TraceRoot);
                    }
                }

                alist = alist.OrderByDescending(t => t.Order()).ToList();
            }
        }

        /// IsMatch 有可能被 覆盖 添加了自身的逻辑， 则需要调用一下
        if (this.IsMatch(inst, ops))
            foreach (var u in alist)
            {
                if (u.IsMatch(inst, ops))
                    return u;
            }

        return null;

    }


    /// <summary>
    /// 覆盖时，不需要再调用 基类方法  
    /// </summary>
    [DebuggerNonUserCode()]
    public virtual bool IsMatch(Inst inst, List<Operand> ops)
    {
        return true;
    }


    // 默认是交给 子类处理 , 具体节点 覆盖此逻辑即可 
    // ftp://note 交由子节的表达式，是自身维护的 表达式， 而不是由上层传过来的 

    public virtual void Do(Inst node, Expr main, List<Operand> ops)
    {
        GetSubMatch(node, ops)?.Do(node, main, ops);
    }

}


class AlterCase : TraceRoot
{

    public override bool IsMatch(Inst inst, List<Operand> ops)
        => ops.HaveAnd(inst.O1);
    // || (inst.Opt == Opt.xchg && ops.HaveAnd(inst.O2));
}

//class XchgCase : AlterCase
//{
//    public override bool IsMatch(Inst inst, List<Operand> ops)
//        => inst.Opt == Opt.xchg;

//    public override void Do(Context con , Inst node,  Expr main, List<Operand> ops ,bool checkFactor)
//    {
//        var inst = node;
//        if (ops.HaveEq(inst.O1))
//        {

//            main.Replace(inst.O1, new Expr { Left = inst.O2, Ext = node });
//            ops.CheckAdd(inst.O2);
//            ops.Remove(inst.O1);

//        }
//        else if (ops.HaveEq(inst.O2))
//        {

//            main.Replace(inst.O2, new Expr { Left = inst.O1, Ext = node });
//            ops.CheckAdd(inst.O1);
//            ops.Remove(inst.O2);
//        }

//        /// 以下是 大于的情况  

//        else if (ops.HaveGe(inst.O1))
//        {
//            /// 如果 已经 存在 赋值， 则不继续 给它赋值了 
//            var exp = main.Find((exp) => exp.Left is Operand lo && lo > inst.O1 && (exp.Opt == Opt.mov));

//            Operand op = ops.GetAnd(inst.O1);
//            if (exp == null)
//            {
//                // 部分赋值， 同 + - 等修饰运算 一样 
//                main.Replace(op, new Expr(op, Opt.mov, inst.O2, node));
//                ops.CheckAdd(inst.O2);
//            }
//            else
//            {

//                if (exp.ByteSize < inst.O2.ByteSize || (inst.O1.IsHighByteOf(inst.O1) && exp.Offset == 0) || (inst.O1.IsLowByteOf(inst.O1) && exp.Offset == 1))
//                {
//                    // 部分赋值， 同 + - 等修饰运算 一样 
//                    main.Replace(exp, new Expr(exp, Opt.mov, inst.O2, node));
//                    ops.CheckAdd(inst.O2);
//                }
//            }

//        }
//        else if (ops.HaveGe(inst.O2))
//        {

//            /// 如果 已经 存在 赋值， 则不继续 给它赋值了 
//            var exp = main.Find((exp) => exp.Left is Operand lo && lo > inst.O2 && (exp.Opt == Opt.mov));

//            Operand op = ops.GetAnd(inst.O2);
//            if (exp == null)
//            {
//                // 部分赋值， 同 + - 等修饰运算 一样 
//                main.Replace(op, new Expr(op, Opt.mov, inst.O1, node));
//                ops.CheckAdd(inst.O1);
//            }
//            else
//            {

//                if (exp.ByteSize < inst.O1.ByteSize || (inst.O2.IsHighByteOf(inst.O1) && exp.Offset == 0) || (inst.O2.IsLowByteOf(inst.O2) && exp.Offset == 1))
//                {
//                    // 部分赋值， 同 + - 等修饰运算 一样 
//                    main.Replace(op, new Expr(op, Opt.mov, inst.O1, node));
//                    ops.CheckAdd(inst.O1);                    // 部分赋值， 同 + - 等修饰运算 一样 
//                }
//            }
//        }

//        /// 以下是 小于的情况  

//        else if (ops.HaveLe(inst.O1))
//        {
//            Operand op = ops.GetAnd(inst.O1);

//            var new_op = inst.O2.ReSize((SizeInfo)op.SizeOf(inst.O1));
//            main.Replace(op, new Expr(new_op, node));
//            ops.CheckAdd(new_op);
//            ops.Remove(op);
//        }
//        else if (ops.HaveLe(inst.O2))
//        {
//            Operand op = ops.GetAnd(inst.O2);

//            var new_op = inst.O1.ReSize((SizeInfo)op.SizeOf(inst.O2));
//            main.Replace(op, new Expr(new_op, node));
//            ops.CheckAdd(new_op);
//            ops.Remove(op);
//        }

//    }
//}

class MovPass : AlterCase
{
    public override bool IsMatch(Inst inst, List<Operand> ops)
        => inst.Opt == Opt.mov;

    public override void Do(Inst node, Expr main, List<Operand> ops)
    {
        var inst = node;
        if (ops.HaveEq(inst.O1))
        {

            main.Replace(inst.O1, new Expr { Left = inst.O2, Ext = node });
            ops.CheckAdd(inst.O2);
            ops.Remove(inst.O1);


        }
        else if (ops.HaveGe(inst.O1))
        {
            /// 如果 已经 存在 赋值， 则不继续 给它赋值了 
            var exp = main.Find((exp) => exp.Left is Operand lo && lo > inst.O1 && (exp.Opt == Opt.mov || exp.Opt == Opt.movzx || exp.Opt == Opt.movsx));

            if (exp == null)
            {
                Operand op = ops.GetAnd(inst.O1);

                // 部分赋值， 同 + - 等修饰运算 一样 
                main.Replace(op, new Expr(op, Opt.mov, inst.O2, node));
                ops.CheckAdd(inst.O2);

            }
            else
            {
                if (exp.Opt == Opt.movzx || exp.Opt == Opt.movsx)
                    return;

                if (exp.ByteSize < inst.O2.ByteSize || (inst.O1.IsHighByteOf(inst.O1) && exp.Offset == 0) || (inst.O1.IsLowByteOf(inst.O1) && exp.Offset == 1))
                {
                    // 部分赋值， 同 + - 等修饰运算 一样 
                    main.Replace(exp, new Expr(exp, Opt.mov, inst.O2, node));
                    ops.CheckAdd(inst.O2);

                }
            }
        }
        else if (ops.HaveLe(inst.O1))
        {
            Operand op = ops.GetAnd(inst.O1);

            var new_op = inst.O2.ReSize((SizeInfo)op.SizeOf(inst.O1));
            main.Replace(op, new Expr(new_op, node));
            ops.CheckAdd(new_op);
            ops.Remove(op);

        }



    }
}

class MovzxPass : AlterCase
{
    public override bool IsMatch(Inst inst, List<Operand> ops)
        => inst.Opt == Opt.movzx;

    public override void Do(Inst node, Expr main, List<Operand> ops)
    {
        var inst = node;
        if (ops.HaveEq(inst.O1))
        {
            main.Replace(inst.O1, new Expr(inst.O2, node));
            ops.CheckAdd(inst.O2);
            ops.Remove(inst.O1);

        }
        else if (ops.HaveGe(inst.O1))
        {
            // 部分赋值， 同 + - 等修饰运算 一样 
            main.Replace(inst.O1, new Expr(inst.O1, Opt.mov, inst.O2, node));
            ops.CheckAdd(inst.O2);
        }
        else if (ops.HaveLe(inst.O1))
        {
            Operand op = ops.GetAnd(inst.O1);

            /// 自已给 自已赋值 
            if (inst.O1 & inst.O2)
            {
                /// movzx ax, al   找 ah
                if (!(op & inst.O2))
                {
                    /// 如果目标是高位 
                    if (op.IsHighByteOf(inst.O2))
                    {
                        // ah 被赋值为0 
                        main.Replace(op, new Expr(Operand.Make(0, op.ByteSize), node));
                        ops.CheckAdd(inst.O2);
                        ops.Remove(op);
                    }
                    else
                    {
                        // ah 被赋值为0 
                        main.Replace(op, new Expr(inst.O2, node));
                        ops.Remove(op);
                    }
                }
                else
                {
                    if (op <= inst.O2)
                    {
                        /// 追踪 ah , 此处是 aw 的情况 
                        return;
                    }
                    else
                    {
                        /// 追踪 aw  , 此处是 al 或 ah 的情况 
                        main.Replace(op, new Expr(inst.O2, node));
                        ops.CheckAdd(inst.O2);
                        ops.Remove(op);
                    }
                }
            }
            else
            {

                var new_op = inst.O2.ReSize((SizeInfo)op.SizeOf(inst.O1));

                /// 如果追踪到是 高字节 
                if (!(new_op & op))
                {
                    main.Replace(op, new Expr(Operand.Make(0, op.ByteSize), node));
                    ops.Remove(op);
                }
                else
                {
                    main.Replace(op, new Expr(new_op, node));
                    ops.CheckAdd(new_op);
                    ops.Remove(op);
                }
            }
        }



    }
}


class MovsxPass : AlterCase
{
    public override bool IsMatch(Inst inst, List<Operand> ops)
        => inst.Opt == Opt.movsx;

    public override void Do(Inst node, Expr main, List<Operand> ops)
    {
        var inst = node;
        if (ops.HaveEq(inst.O1))
        {
            main.Replace(inst.O1, new Expr(inst.O2, node));
            ops.CheckAdd(inst.O2);
            ops.Remove(inst.O1);

        }
        else if (ops.HaveGe(inst.O1))
        {
            // 部分赋值， 同 + - 等修饰运算 一样 
            main.Replace(inst.O1, new Expr(inst.O1, Opt.movsx, inst.O2, node));
            ops.CheckAdd(inst.O2);
        }
        else if (ops.HaveLe(inst.O1))
        {
            Operand op = ops.GetAnd(inst.O1);

            var new_op = inst.O2.ReSize((SizeInfo)op.SizeOf(inst.O1));

            main.Replace(op, new Expr(new_op, node));
            if (!new_op.IsImm)
                ops.CheckAdd(new_op);
            ops.Remove(op);
        }



    }
}

/// <summary>
/// 退栈
/// </summary>
class PopPass : AlterCase
{
    public override bool IsMatch(Inst inst, List<Operand> ops)
        => inst.Opt == Opt.pop;

    public override void Do(Inst node, Expr main, List<Operand> ops)
    {
        var inst = node;

        Operand o = Operand.Make(inst.O1.ByteSize, inst.Is64Bit ? RegCode.rsp : RegCode.esp, 0);

        ops.CheckAdd(o);

        if (ops.HaveEq(inst.O1))
        {

            ops.RemoveLe(inst.O1);

            main.Replace(inst.O1, new Expr(o, node));
        }
        else if (ops.HaveGe(inst.O1))
        {
            var op = ops.GetAnd(inst.O1);
            // 部分赋值， 同 + - 等修饰运算 一样 

            main.Replace(op, new Expr { Left = op, Opt = Opt.mov, Right = o, Ext = node });


        }
    }
}

/// <summary>
/// lea语句
/// </summary>
class LeaPass : AlterCase
{

    public override bool IsMatch(Inst inst, List<Operand> ops)
        => inst.Opt == Opt.lea;

    public override void Do(Inst node, Expr main, List<Operand> ops)
    {
        var inst = node;

        var fix = inst.ExpOp.Copy();
        fix.Recursion((o) =>
        {
            if (o.Left is RegCode bs)
                o.Left = new Operand(bs);
            if (o.Right is RegCode rs)
                o.Right = new Operand(rs);
        });

        if (main.Left == null)
        {
            main.Left = fix;
        }
        else
        {
            main.Replace(inst.O1, new Expr { Left = fix, Ext = node });
        }

        ops.RemoveLe(inst.O1);
        List<Operand> list = new List<Operand>();
        list.Collect(inst.ExpOp);
        list.ForEach(op => { ops.CheckAdd(op); });

    }
}

/// <summary>
/// 单操作数
/// </summary>
class UnaryCase : AlterCase
{

    protected override int Order() => 0;

    public override bool IsMatch(Inst inst, List<Operand> ops)
    {
        return inst.Is_Unary;
    }

    public override void Do(Inst node, Expr main, List<Operand> ops)
    {
        var inst = node;

        main.Replace(inst.O1, new Expr { Left = inst.O1, Ext = node, Opt = inst.Opt });
    }
}

/// <summary>
/// 双操作数
/// </summary>
class BinCase : AlterCase
{
    protected override int Order() => 0;

    public override bool IsMatch(Inst inst, List<Operand> ops)
    {
        return !inst.Is_Unary;
    }

    /*********
     * 如果正在追踪 eax , 此时出现 add al, xxx ; 
     * 此时可以截止追踪 
     * ******/
    public override void Do(Inst node, Expr main, List<Operand> ops)
    {
        var inst = node;
        if (!ops.HaveEq(inst.O1))
        {
            ops.RemoveGe(ref inst.O1);
        }
        else
        {

            main.Replace(inst.O1, new Expr { Left = inst.O1, Ext = node, Opt = inst.Opt, Right = inst.O2.IsImm ? (ulong)inst.O2.u64 : inst.O2 });

            ops.CheckAdd(inst.O2);

        }

    }
}



